export function DataFomatter(ctx) {

  let context = ctx;

  /**---------------------------------------------------------------------------
   *计算nodes与links内部必要属性
   */
  this.formatData = function() {
    let kg = context.kgInfo;

    this.formatNodes(kg.nodes);
    this.formatLinks(kg.links);
  }

  /**---------------------------------------------------------------------------
   * 计算nodes内部必要属性
   * @param nodes
   * @returns {*} 无返回值 直接在传入数组内部修改
   */
  this.formatNodes = function(nodes) {
    let _this = context;

    //初始化nodes相关属性
    nodes.forEach(function(n) {
      if (n.center === 1 || n.center === "1") {
        n.fx = _this.width / 2;
        n.fy = _this.height / 2;
      }
      if (typeof n.fx === "undefined" || n.fx === "") {
        n.fx = null;
      }
      if (typeof n.fy === "undefined" || n.fy === "") {
        n.fy = null;
      }

      n.r = n.selfR?
        n.selfR: //优先级1：自定义节点半径
        n.type.r; //优先级2：节点所属类型半径;

      n.color = n.selfColor?
        n.selfColor: //优先级1：自定义节点颜色
        n.type.color; //优先级2：节点所属类型颜色
    });
  }

  /**---------------------------------------------------------------------------
   * 计算links内部必要属性
   * @returns {[]} 无返回值 直接在传入数组内部修改
   * @param links
   */
  this.formatLinks = function(links) {
    let nodes = context.kgInfo.nodes;

    links.forEach(function(m) {
      let sourceNode = nodes.filter(function(n) {
        return n.uuid === m.sId;
      })[0];
      if (!sourceNode) return;
      let targetNode = nodes.filter(function(n) {
        return n.uuid === m.tId;
      })[0];
      if (!targetNode) return;

      m.source = sourceNode.uuid;
      m.target = targetNode.uuid;
    });
    formatLinksAttr(links)
  }

  /**---------------------------------------------------------------------------
   * 计算links弧度相关属性
   * @param links
   * @returns {[]}
   */
  function formatLinksAttr(links) {
    let formatLinks = [];
    let linkGroupArr = [];
    links.forEach(function(link) {
      let added = false;
      for (let i = 0; i < linkGroupArr.length; i++) {
        if (
          (linkGroupArr[i][0].source == link.source &&
            linkGroupArr[i][0].target == link.target) ||
          (linkGroupArr[i][0].source == link.target &&
            linkGroupArr[i][0].target == link.source)
        ) {
          linkGroupArr[i].push(link);
          added = true;
          break;
        }
      }
      if (!added) {
        linkGroupArr.push([link]);
      }
    });
    linkGroupArr.forEach(function(group) {
      let groupSource = group[0].sId;
      group.forEach(function(link, index) {
        link.linkDirection = link.source == groupSource;
        link.linkGroupIndex = index + 1;
        link.groupLinkTotal = group.length;
        formatLinks.push(link);
      });
    });
    formatLinks.forEach(function(item) {
      //线的单双，单数且小于2，则只有一条直线，大于2且单数，有多条弧线和一条直线
      let groupLinkTotalHalf = item.groupLinkTotal / 2;
      //能否被2整除，是否有余数，true=有，false=没有，有余数必然有一条直线
      item.groupLinkUneven = item.groupLinkTotal % 2 !== 0;
      //判断是否是最中间的直线（有余数，并且序号刚好是本组连线的一版，这里向上取整）
      item.groupLinkMiddle =
        item.groupLinkUneven === true &&
        Math.ceil(groupLinkTotalHalf) === item.linkGroupIndex;
      //假设有一条直线，index刚好是groupLinkTotalHalf的值，上方的曲线都为0，下方的曲线都为1
      var groupLinkLowerHalf = item.linkGroupIndex <= groupLinkTotalHalf;
      //上方的曲线和直线方向一致，下方的曲线和直线的方向相反
      item.groupLinkArcDirection =
        (groupLinkLowerHalf && item.linkDirection) ||
        (!groupLinkLowerHalf && !item.linkDirection)
          ? 0
          : 1;
      // item.groupLinkArcDirection = 1;
      //都在直线上方，则取当前序号，否则减去中间直线取序号
      item.groupLinkIndexCorrected = groupLinkLowerHalf
        ? item.linkGroupIndex
        : item.linkGroupIndex - Math.ceil(groupLinkTotalHalf);
      item.groupLinkMaxHalf = Math.round(item.groupLinkTotal / 2);
    });
    // return formatLinks;
  }

  /**---------------------------------------------------------------------------
   * 修改颜色、半径
   * @param obj
   * @param modal
   * @param propertyName 显示属性名
   * @param selfPropertyName 自定义属性记录属性名
   */
  this.modifyProperty = function(obj, modal,propertyName,selfPropertyName) {

    //| isColorChanged isOldSelfDefined | isNewSelfDefined | option | withdraw |
    //| --- | --- | --- | --- | --- |
    //| 0 | 0 | 0 | 未修改属性; | 000 |
    //| 0 | 0 | 1 | error | error |
    //| 0 | 1 | 0 | 之前自定义过属性,本次操作未修改属性; | 011 |
    //| 0 | 1 | 1 | 010撤回;  | null |
    //| 1 | 0 | 0 | 之前未自定义过属性，本次自定义了属性; | 110 |
    //| 1 | 0 | 1 |  |  |
    //| 1 | 1 | 0 | 之前自定义过属性，再次自定义属性;100撤回; | 111 |
    //| 1 | 1 | 1 |  | 110撤回; |

    //isNewSelfDefined为1一定都是撤回操作

    let isChanged = obj[propertyName] !== modal[propertyName];
    let isOldSelfDefined = ((obj[selfPropertyName] !== undefined) && (obj[selfPropertyName] !== null));
    let isNewSelfDefined = ((modal[selfPropertyName] !== undefined) && (modal[selfPropertyName] !== null));

    if (!isChanged && !isOldSelfDefined && !isNewSelfDefined) { //000---
      //nothing to do
    }
    else if (!isChanged && !isOldSelfDefined && isNewSelfDefined) { //001---
      throw "modify property error:code 001.";
    }
    else if (!isChanged && isOldSelfDefined && !isNewSelfDefined) { //010---
      //nothing to do
    }
    else if (!isChanged && isOldSelfDefined && isNewSelfDefined) { //011---
      //nothing to do
    }
    else if(isChanged && !isOldSelfDefined && !isNewSelfDefined) { //100---
      obj[selfPropertyName] = modal[propertyName];
      obj[propertyName] = modal[propertyName];
    }
    else if(isChanged && !isOldSelfDefined && !isNewSelfDefined) { //101---
      throw "modify property error:code 101.";
    }
    else if(isChanged && isOldSelfDefined && !isNewSelfDefined) { //110---
      if(modal[selfPropertyName] === null) obj[selfPropertyName]=null; //100撤回
      else obj[selfPropertyName] = modal[propertyName];
      obj[propertyName] = modal[propertyName];
    }
    else if(isChanged && isOldSelfDefined && isNewSelfDefined) { //111---
      obj[selfPropertyName] = modal[selfPropertyName];
      obj[propertyName] = modal[propertyName];
    }
    else throw "unknown condition in modify property";

    return isChanged;

  }


}